<template>
  <el-dialog title="新增测试用例" v-model="isAddCase" width="30%">
    <el-form
      ref="caseFormRef"
      :rules="newCaseRules"
      :model="newCase"
      label-width="80px"
      :inline="false"
      size="default"
    >
      <el-form-item label="用例名" prop="caseName">
        <el-input v-model="newCase.caseName"></el-input>
      </el-form-item>
    </el-form>

    <template #footer>
      <span>
        <el-button @click="closeCaseAdder">取消</el-button>
        <el-button type="primary" @click="addCase">确认</el-button>
      </span>
    </template>
  </el-dialog>

  <el-dialog title="新增测试步骤" v-model="isAddStep" width="30%">
    <el-form :model="newCase" label-width="80px" :inline="false" size="default">
      <el-form-item label="用例名">
        <el-select v-model="newCase.parentId" clearable filterable>
          <el-option
            v-for="item in caseNameList"
            :key="item.id"
            :label="item.caseName"
            :value="item.id"
          >
          </el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="步骤名">
        <el-input v-model="newCase.stepName"></el-input>
      </el-form-item>
      <el-form-item label="关键字">
        <el-select
          v-model="newCase.keywords"
          placeholder="请选择关键字"
          clearable
          filterable
        >
          <el-option
            v-for="item in keywordsInfoList"
            :key="item.keywords"
            :label="item.name"
            :value="item.keywords"
          >
          </el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="参数1">
        <el-input v-model="newCase.param1"></el-input>
      </el-form-item>
      <el-form-item label="参数2">
        <el-input v-model="newCase.param2"></el-input>
      </el-form-item>
    </el-form>

    <template #footer>
      <span>
        <el-button @click="closeCaseAdder">取消</el-button>
        <el-button type="primary" @click="addStep">确认</el-button>
      </span>
    </template>
  </el-dialog>

  <el-card
    shadow="always"
    :body-style="{
      padding: '20px',
      height: 'calc(100vh - 165px)',
    }"
  >
    <template #header>
      <div>
        <el-row :gutter="20">
          <el-col :span="7"
            ><span class="case-title">{{
              moduleStore.selectedModule.name
            }}</span></el-col
          >
          <el-col :span="17" style="text-align: right">
            <el-dropdown>
              <el-button type="success" :icon="Plus">
                新增<el-icon class="el-icon--right"><arrow-down /></el-icon>
              </el-button>
              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item @click="openCaseAdder"
                    >用例</el-dropdown-item
                  >
                  <el-dropdown-item @click="openStepAdder"
                    >步骤</el-dropdown-item
                  >
                </el-dropdown-menu>
              </template>
            </el-dropdown>

            <el-button
              type="primary"
              size="default"
              :icon="Promotion"
              @click="changeCase"
              >提交修改
            </el-button>
            <el-button
              type="danger"
              size="default"
              :icon="Delete"
              @click="deleteChecked"
              :disabled="checkedIds?.length === 0"
              >删除选中用例
            </el-button>
            <el-button
              type="primary"
              size="default"
              :icon="Grid"
              @click="expandTreeOrNot"
              >展开/折叠
            </el-button>
          </el-col>
        </el-row>
      </div>
    </template>

    <vxe-table
      ref="caseTable"
      border
      show-overflow
      height="100%"
      :row-config="{ keyField: 'id' }"
      :tree-config="{
        children: 'children',
        rowField: 'id',
        parentField: 'parentId',
        reserve: true,
        trigger: 'row',
      }"
      :column-config="{ resizable: true }"
      :data="treeCaseList"
      :edit-config="{ trigger: 'dblclick', mode: 'row' }"
    >
      <vxe-column type="checkbox" width="60" tree-node></vxe-column>
      <vxe-column
        field="caseName"
        title="用例名"
        width="150"
        :edit-render="{ name: 'input' }"
      >
        <template #edit="{ row }">
          <vxe-input
            v-model="row.caseName"
            type="text"
            :disabled="row.parentId && row.caseName.length === 0"
          ></vxe-input>
        </template>
      </vxe-column>
      <vxe-column
        field="stepName"
        title="步骤名"
        :edit-render="{ name: 'input' }"
      >
        <template #edit="{ row }">
          <vxe-input
            v-model="row.stepName"
            type="text"
            :disabled="!row.parentId || row.caseName.length > 0"
          ></vxe-input>
        </template>
      </vxe-column>
      <vxe-column
        field="keywords"
        title="关键字"
        :edit-render="{ name: 'select' }"
      >
        <template #edit="{ row }">
          <vxe-select
            v-model="row.keywords"
            :disabled="!row.parentId || row.caseName.length > 0"
            transfer
            filterable
          >
            <vxe-option
              v-for="item in typeKeywordsList"
              :key="item.keywords"
              :value="item.keywords"
              :label="item.name"
            ></vxe-option>
          </vxe-select>
        </template>
      </vxe-column>
      <vxe-column field="param1" title="参数1" :edit-render="{}">
        <template #edit="{ row }">
          <vxe-input
            v-model="row.param1"
            type="text"
            placeholder="请输入第一个参数"
            :disabled="!row.parentId || row.caseName.length > 0"
          ></vxe-input>
        </template>
      </vxe-column>
      <vxe-column field="param2" title="参数2" :edit-render="{}">
        <template #edit="{ row }">
          <vxe-input
            v-model="row.param2"
            type="text"
            placeholder="请输入第二个参数"
            :disabled="!row.parentId || row.caseName.length > 0"
            transfer
          ></vxe-input>
        </template>
      </vxe-column>
      <vxe-column title="操作" :width="200">
        <template #default="{ row }">
          <el-button
            type="success"
            size="default"
            :icon="Plus"
            @click.stop="insertRow(row)"
            >新增</el-button
          >
          <el-button
            type="danger"
            size="default"
            :icon="Delete"
            @click.stop="deleteCase(row)"
            >删除</el-button
          >
        </template>
      </vxe-column>
    </vxe-table>
  </el-card>
</template>

<script lang="ts" setup>
import { ref, reactive, onMounted, computed, watch, onUnmounted } from "vue";
import {
  Delete,
  Plus,
  Promotion,
  Grid,
  ArrowDown,
} from "@element-plus/icons-vue";
import type { SunnyCase, CaseShow } from "@/types/sunnyCase/types";
//使用index.ts命名相当于访问路径时的默认索引，可以不加文件名，不过看自己的命名习惯来选择即可
import {
  addCaseApi,
  delCaseApi,
  changeCaseApi,
  listCaseInModuleApi,
} from "@/api/sunnycase";
import type { VxeTableInstance } from "vxe-table";
import XEUtils from "xe-utils";
import { ElMessage, type FormInstance, type FormRules } from "element-plus";
import Sortable from "sortablejs";
import { useKeywordsStore } from "@/stores/keywordsStore";
import { storeToRefs } from "pinia";
import { onBeforeRouteUpdate, useRoute } from "vue-router";
import { useModuleStore } from "@/stores/sunnyModuleStore";
const keywordsStore = useKeywordsStore();
const moduleStore = useModuleStore();
const { originKeywordsList, keywordsInfoList } = storeToRefs(keywordsStore);
//基于已经选中的模块的type类型过滤keywords
const typeKeywordsList = computed(() => {
  return keywordsInfoList.value.filter((ele) => {
    return ele.type === moduleStore.selectedModule.type;
  });
});
console.log(originKeywordsList);
console.log(keywordsInfoList);

//在挂载阶段获取服务端上的数据
onMounted(() => {
  console.log("挂载case组件");
  listCases();
  keywordsStore.listKeywords();
  initSortable();
});

/** vxetable对象 */
let caseTable = ref<VxeTableInstance>();

/** 树形结构用例数据类型接口 */
interface TreeSunnyCase extends SunnyCase {
  children?: SunnyCase[];
}

/**用例新增表单模板对象 */
const caseFormRef = ref<FormInstance>();

//isAdd用于控制是否显示新增组件。
let isAddCase = ref(false);
let isAddStep = ref(false);

/** 用例数据，用于和后端进行交互 */
let caseList = ref<SunnyCase[]>([]);

/** 用于和用例信息表单进行绑定 */
let newCase = reactive<CaseShow>({
  caseName: "新增用例",
  stepName: "新步骤",
  keywords: "新关键字",
  param1: "",
  param2: "",
  parentId: null,
});
/**
 * 空模板，不需要响应式
 */
let emptyCase: CaseShow = {
  caseName: "",
  stepName: "",
  keywords: "",
  param1: "",
  param2: "",
  parentId: null,
};

/**转换为树形结构的用例数据 */
let treeCaseList = computed(() => {
  //验证caseList的变化中X_ROW_KEY是treecaseTable绑定了vxetable之后产生的。在绑定之前就有了children
  // XEUtils.toArrayTree(caseList.value);
  // return [];
  return XEUtils.toArrayTree(caseList.value, {
    sortKey: "sortId",
  }) as TreeSunnyCase[];
});

/**获取所有用例行的id和名字 */
let caseNameList = computed(() => {
  return treeCaseList.value.map((element) => {
    return { id: element.id, caseName: element.caseName };
  });
});

/**设置表单校验规则 */
const newCaseRules = reactive<FormRules>({
  caseName: [{ required: true, message: "用例名必须填写", trigger: "blur" }],
});

//监视caseList
watch(caseList, (newValue, oldValue) => {
  console.log(
    "caseLIst发生了变化，原本的值是:",
    oldValue,
    "新的值是:",
    newValue
  );
});

//基于caseTable的变化，来实时计算选中的id。
const checkedIds = computed(() => {
  return caseTable.value?.getCheckboxRecords().map((sunnycase) => {
    return sunnycase.id;
  });
});

//路由对象
const route = useRoute();

// watch(
//   () => {
//     return route.fullPath;
//   },
//   () => {
//     listCases();
//   }
// );

//其实是在页面跳转之前来进行操作,实际上要拿的是to的params中的moduleId，所以不能复用listCases了，而是需要重新写一下请求
onBeforeRouteUpdate((to) => {
  //通过Number方法调用，实际上是通过构造函数构造一个number类型的变量
  listCaseInModuleApi(Number(to.params.moduleId))
    .then(({ data }) => {
      caseList.value = data;
    })
    .catch((error: any) => {
      ElMessage.error(error);
    })
    .then(() => {
      regenerateSortId();
    });
});

/**
 * 删除一行用例
 * @param mycase 当前用例
 */
function deleteCase(mycase: TreeSunnyCase) {
  changeCaseApi(caseList.value).then(() => {
    console.log("要删除的用例是：", mycase);
    //前端完成删除
    // caseList.value.splice(caseList.value.indexOf(mycase), 1);
    //完成字符串的拼接，删除之后，重新获取数据
    // delCaseApi(mycase.id + "").then(() => {
    //   listCases();
    // });

    //tree表格，可以直接用remove来完成删除，但是不影响响应式数据，所以不用这种形式
    // caseTable.value?.remove(mycase).then(() => {
    //   treeCaseList.value.splice(treeCaseList.value.indexOf(mycase), 1);
    //   caseList.value = XEUtils.toTreeArray(treeCaseList.value);
    //   console.log("删除之后tree的值是", treeCaseList.value);
    //   console.log("删除之后list的值是", caseList.value);
    // });

    //先判断有没有children，有的话需要把children的值也拿出来
    if (mycase.children?.length! > 0) {
      //有children的时候，要删除的用例包含children中的每个id，和条用例自己的id
      let childrenIds = mycase.children!.map((element) => {
        return element.id;
      });
      //将父用例id插入到数组第一位
      childrenIds.unshift(mycase.id);
      console.log("要删除的用例id是" + childrenIds);
      //删除用例的请求
      delCaseApi(childrenIds.toString()).then(() => {
        listCases();
      });
    } else {
      delCaseApi(mycase.id + "").then(() => {
        listCases();
      });
    }
  });
}

/**
 * 删除选中用例，在树形结构下不需要调整。获取到的id包含子步骤的id。
 */
function deleteChecked() {
  changeCaseApi(caseList.value).then(() => {
    console.log("选中的id是", checkedIds.value?.toString());
    // let idstring = "";
    // for (let index = 0; index <script checkedIds.value!.length; index++) {
    //   if (index === checkedIds.value!.length - 1) {
    //     idstring += checkedIds.value![index];
    //   } else {
    //     idstring += checkedIds.value![index] + ",";
    //   }
    // }

    delCaseApi(checkedIds.value!.toString()).then(() => {
      listCases();
    });
  });
}

function addCase() {
  //第一次新增用例，不用更新。
  if (caseList.value.length > 0) {
    changeCaseApi(caseList.value).then(() => {
      requestAddCase();
    });
  } else {
    requestAddCase();
  }
}

/**
 * 新增用例
 */
async function requestAddCase() {
  await caseFormRef.value!.validate((valid, fields) => {
    if (valid) {
      let lastId =
        caseList.value.length > 0
          ? caseList.value[caseList.value.length - 1].id
          : -1;
      //扩展操作符赋值，深拷贝
      let newAddCase: SunnyCase = {
        ...emptyCase,
        id: 0,
        //创建用例时，不会每次都重新提交更新所有的sortId，
        //所以第一个创建的用例的sortId在数据库没更新但是前端界面更新了
        //如果还没有用例的时候，sortId创建为1，有用例了就创建为和当前最大的用例sortId一致
        sortId: 1000,
        // caseList.value.length > 0
        //   ? caseList.value
        //       .filter((ele) => {
        //         return !ele.parentId;
        //       })
        //       .reduce((prev, cur) => {
        //         return prev.sortId > cur.sortId ? prev : cur;
        //       }).sortId
        //   // : 1,
        moduleId: moduleStore.selectedModule.id,
      };
      //如果直接push newCase是浅拷贝，会导致每次添加的元素都一起变化
      newAddCase.id = lastId + 1;
      newAddCase.author = "roy";
      newAddCase.caseName = newCase.caseName;
      console.log("要新增的用例是", newAddCase);
      // caseList.value.push(addCase);
      //这个方法注意，是axios实现的异步的方法。
      addCaseApi(newAddCase).then(() => {
        //在axios请求完成之后，promise被兑现了再执行listCase()
        listCases();
      });
      closeCaseAdder();
    } else {
      ElMessage.error("输入的用例名不能为空" + fields);
      console.log(fields);
    }
  });
}

/**
 * 新增步骤
 */
function addStep() {
  let lastId =
    caseList.value.length > 0
      ? caseList.value[caseList.value.length - 1].id
      : -1;
  let newStep: SunnyCase = {
    ...newCase,
    id: 0,
    sortId: 1000,
    moduleId: moduleStore.selectedModule.id,
  };
  newStep.id = lastId + 1;
  newStep.author = "roy";
  if (newStep.parentId) {
    //查找一下父元素，然后找到其中最后一条步骤的sortId，作为newStep的sortId
    let parentCase = treeCaseList.value.find((ele) => {
      return ele.id === newStep.parentId;
    });
    console.log("父级的case是", parentCase);
    //如果用例中已经有步骤，那么sortId为最后一条步骤的sortId，否则为1。
    newStep.sortId =
      parentCase!.children!.length > 0
        ? parentCase!.children![parentCase!.children!.length - 1].sortId
        : 1;
    console.log("要新增的步骤是", newStep);
    newStep.caseName = "";
    addCaseApi(newStep).then(() => {
      listCases();
    });
  } else {
    ElMessage.error(
      "新增步骤必须添加到某个用例上，而现在没有对应的用例，新增失败"
    );
  }
  closeCaseAdder();
}

/**
 * 插入一行用例（步骤）
 */
function insertRow(row: SunnyCase) {
  //vxe-table所提供的插入方法进行调用，注意是不会影响组件中的数据的。
  // let insertedRow;
  // let newinsertCase = emptyCase;
  // emptyCase.caseName = "royInsert";
  // caseTable.value?.insert(newinsertCase).then(({ row: newRow }) => {
  //   insertedRow = newRow;
  //   console.log(insertedRow);
  //   caseTable.value?.setEditRow(insertedRow);
  // });

  //通过请求接口完成服务端的业务逻辑调用，再反过来影响前端内容。
  //排序的sortId字段跟当前行保持一致，利用相同sortId按id排序的原则，让它排到下面。
  changeCaseApi(caseList.value).then(() => {
    let newCaseRow: SunnyCase = {
      ...emptyCase,
      id: 0,
      author: "roy",
      sortId: row.sortId,
      moduleId: moduleStore.selectedModule.id,
    };
    console.log("要添加的用例是", newCaseRow);
    if (row.parentId) {
      //步骤
      newCaseRow.stepName = "新增步骤";
      //新增步骤和当前行是在同一个用例中的，所以parentId相等
      newCaseRow.parentId = row.parentId;
    } else {
      //用例
      newCaseRow.caseName = "新增用例";
    }
    //调用新增用例接口，并且获取用例刷新
    addCaseApi(newCaseRow).then(() => {
      listCases();
    });
  });
}

//修改用例的实际回调函数。
function changeCase() {
  changeCaseApi(caseList.value).then(() => {
    listCases();
  });
}

//用于关闭Adder组件
function closeCaseAdder() {
  isAddCase.value = false;
  isAddStep.value = false;
  //重置一下newCase的数据为空
  newCase.value = emptyCase;
}

//打开用例新增窗口
function openCaseAdder() {
  isAddCase.value = true;
}

//打开步骤新增窗口
function openStepAdder() {
  isAddStep.value = true;
}

/** 请求后端获取用例数据 */
function listCases() {
  // let expandedTree = caseTable.value?.getTreeExpandRecords();
  // let expandedIds = expandedTree?.map((ele) => {
  //   return ele.id;
  // });
  // console.log("需要展开的用例是", expandedTree);
  // listCaseApi()
  listCaseInModuleApi(Number(route.params.moduleId))
    //then中回调函数的参数，是promise的返回
    // .then((resp) => {
    //   console.log("拿到的返回结果是", resp);
    // })
    //解构赋值，把resp中的data单独拿出来
    .then(({ data }) => {
      //如果一个对象的值是可能需要重新赋值的，就用ref
      caseList.value = data;
      // console.log("展开用例", expandedTree);
      //在这里执行会导致页面还没有渲染完，就开始进行展开操作了
      // //如果直接操作，由于key的变化，导致展开无效。
      // //需要展开的其实是treeCaseTable中，id在expandedIds中的行
      // let tree2ex = treeCaseList.value.filter((ele) => {
      //   return expandedIds?.includes(ele.id);
      // });
      // console.log("需要展开的用例有",tree2ex);
      // caseTable.value?.setTreeExpand(tree2ex, true);
      // convertTree();
    })
    .catch((error: any) => {
      ElMessage.error(error);
    })
    .then(() => {
      regenerateSortId();
    });
  // //放在这里进行处理，在caseList赋值完成之后再执行，就可以正常展开。
  // .then(() => {
  //   // let tree2ex = treeCaseList.value.filter((ele) => {
  //   //   return expandedIds?.includes(ele.id);
  //   // });
  //   // console.log("需要展开的用例有", tree2ex);
  //   caseTable.value?.setTreeExpand(expandedTree, true);
  // });
}

/** 查询模块中的用例数据 */
function listCasesInModule() {
  listCaseInModuleApi(1)
    .then(({ data }) => {
      caseList.value = data;
    })
    .catch((error: any) => {
      ElMessage.error(error);
    })
    .then(() => {
      regenerateSortId();
    });
}

/** 展开/折叠树形结构 */
function expandTreeOrNot() {
  caseTable.value?.getTreeExpandRecords().length! > 0
    ? caseTable.value?.clearTreeExpand()
    : caseTable.value?.setAllTreeExpand(true);
}

/**重新整理所有的用例和步骤行的sortId
 * 按照人类逻辑，sortId从1开始，递增排列
 * 按照当前页面上treeCase的下标来赋值sortId
 * 由于treeCaseList中的元素是通过caseList浅拷贝来的，所以修改之后直接影响caseList。
 */
function regenerateSortId() {
  let caseSortId = 0;
  treeCaseList.value.forEach((treeCase) => {
    caseSortId += 1;
    treeCase.sortId = caseSortId;
    if (treeCase.children) {
      for (let i = 0; i < treeCase.children.length!; i++) {
        treeCase.children[i].sortId = i + 1;
      }
    }
  });
}

//拖拽实例对象
let sortableTable: Sortable;

function initSortable() {
  if (caseTable.value) {
    let tablebody = (caseTable.value?.$el as HTMLElement).querySelector(
      "table.vxe-table--body >tbody"
    );
    sortableTable = Sortable.create(tablebody as HTMLElement, {
      animation: 150,
      ghostClass: "ghost",
      onEnd: ({ item, oldIndex, newIndex }) => {
        //原生DOM元素
        const dragElement = item;
        const parentElement = dragElement.parentElement as HTMLElement;
        const prevELement = dragElement.previousElementSibling as HTMLElement;
        const nextElement = dragElement.nextElementSibling as HTMLElement;

        console.log("拖动的元素是,", item);
        console.log("拖动完成后的父元素是,", parentElement);
        console.log("拖动完成后的前一个元素是,", prevELement);
        console.log("拖动完成后的后一个元素是,", nextElement);

        //vxeTable中的row节点
        const curRow = caseTable.value!.getRowNode(dragElement);
        const prevRow = caseTable.value!.getRowNode(prevELement);
        const nextRow = caseTable.value!.getRowNode(nextElement);
        console.log("当前操作的行对应在vxeTable组件中curRow是", curRow);
        console.log("当前操作的行对应在vxeTable组件中prevRow是", prevRow);
        console.log("当前操作的行对应在vxeTable组件中nextRow是", nextRow);

        //treeCaseList数据中的节点
        const curNode = XEUtils.findTree(treeCaseList.value, (row) => {
          return row === curRow?.item;
        });
        const prevNode = XEUtils.findTree(treeCaseList.value, (row) => {
          return row === prevRow?.item;
        });
        const nextNode = XEUtils.findTree(treeCaseList.value, (row) => {
          return row === nextRow?.item;
        });
        // console.log(
        //   "当前操作行对应在treeCaseList中操作的curNode节点是,",
        //   curNode
        // );
        // console.log(
        //   "当前操作行对应在treeCaseList中操作的prevNode节点是,",
        //   prevNode
        // );
        // console.log(
        //   "当前操作行对应在treeCaseList中操作的nextNode节点是,",
        //   nextNode
        // );

        //拖动逻辑
        //是步骤还是用例
        if (curRow?.parent) {
          //这是步骤行
          if (!prevELement) {
            //步骤行不能拖到第一行
            ElMessage.error("步骤行不能移动到第一行!");
            //通过dom元素的插入操作完成还原
            parentElement.insertBefore(
              dragElement,
              parentElement.children[(oldIndex as number) + 1]
            );
          } else if (!nextElement) {
            curRow!.item.sortId = 1000;
            if (prevRow?.parent) {
              //上一行是步骤行
              //当前行的parentId和上一行变成相同的
              curRow!.item.parentId = prevRow.item.parentId;
            } else {
              //上一行是用例行,所以把当前行的parentId设置为上一行的id
              curRow.item.parentId = prevRow?.item.id;
              //为了看起来更友好，展开这个用例行
              caseTable.value?.setTreeExpand(prevRow!.item, true);
            }
          } else {
            //非首尾行
            if (prevRow?.parent) {
              //上一行是个步骤行
              //不管是不是来自于相同用例中的步骤，都要设置parentId和上一行步骤行的一致
              curRow!.item.parentId = prevRow.item.parentId;
              curRow!.item.sortId = prevRow.item.sortId + 0.5;
            } else {
              //上一行是用例行,所以把当前行的parentId设置为上一行的id
              curRow!.item.parentId = prevRow!.item.id;
              //下一行是个步骤行，这个时候，它一定是用例的第一条步骤
              if (nextRow?.parent) {
                //因为是第一条步骤，所以直接为0
                curRow!.item.sortId = 0;
              } else {
                //下一行是个用例行，那么把步骤行插入到上一个用例行中，并且展开上个用例行，sortId设置为最大
                curRow.item.sortId = 1000;
                //为了看起来更友好，展开这个用例行
                caseTable.value?.setTreeExpand(prevRow!.item, true);
              }
            }
          }
        } else {
          //这是用例行
          if (!prevELement) {
            //没有前一个元素，也就是拖到了第一行
            //设置当前拖动的用例行，修改sortId为0,为了保证0是最小的，每次排完之后，都重新计算sortId
            curRow!.item.sortId = 0;
          } else if (!nextElement) {
            //拖到最后一行
            curRow!.item.sortId = 1000;
          } else {
            //中间的位置
            //判断下一行是不是步骤行
            if (nextRow!.parent) {
              //下一行是步骤行，是不允许拖动的
              ElMessage.error("不允许将用例拖拽到用例中！");
              console.log("新的下标的位置是", newIndex);
              console.log(
                "++++++++++++++++++++++++",
                "初始的下标位置是",
                oldIndex,
                "现在这个下标的元素是",
                parentElement.children[oldIndex as number],
                "下一个元素是",
                parentElement.children[(oldIndex as number) + 1]
              );
              console.log("新的下标的位置是", newIndex);
              parentElement.insertBefore(
                dragElement,
                parentElement.children[
                  //如果oldIndex小于newIndex是往下拖，用 oldIndex作为恢复下标
                  oldIndex! < newIndex!
                    ? (oldIndex as number)
                    : //往上拖，用oldIndex+1作为恢复下标
                      (oldIndex as number) + 1
                ]
              );
            } else {
              //下一行是用例行，修改当前行的sortId让其下的步骤也发生变化
              //注意是跟随下一行的sortId发生变化，不能按上一行的，因为上一行有可能是步骤行
              curRow!.item.sortId = nextRow!.item.sortId - 0.5;
            }
          }
          //只要是个用例行，就判断一下当前行是否为展开状态，如果是，取消展开，再重新展开
          if (caseTable.value?.isTreeExpandByRow(curRow!.item)) {
            //返回为Promise，所以在then里面写
            caseTable.value.setTreeExpand(curRow?.item, false).then(() => {
              caseTable.value?.setTreeExpand(curRow?.item, true);
            });
          }
        }
        //不管拖用例还是拖步骤，只要完成一次拖动，就要重新计算一次sortId
        regenerateSortId();
      },
    });
  }
}

onUnmounted(() => {
  if (sortableTable) {
    sortableTable.destroy();
  }
});

// let treeExpanded: any;
// function getTreeExpandRecords() {
//   treeExpanded = caseTable.value?.getTreeExpandRecords();
//   console.log("当前展开的记录为", treeExpanded);
// }

// function resetTreeExpandRecords() {
//   caseTable.value?.setTreeExpand(treeExpanded, true);
//   console.log("当前展开的记录为", treeExpanded);
// }

// function convertTree() {
//   treeCaseList.value = XEUtils.toArrayTree(caseList.value);
//   console.log("转换为树形结构的列表是", treeCaseList);
//   console.log("进行转换后原数组的值是", caseList);
//   let caseFromTreeList = XEUtils.toTreeArray(treeCaseList.value);
//   console.log("转回来的数组的值是", caseFromTreeList);
// }

// function reValueTree() {
//   treeCaseList.value = [];
// }
</script>

<style scoped>
.case-title {
  font-size: larger;
  font-weight: bolder;
}
.el-dropdown {
  margin-right: 12px;
}

.ghost {
  background-color: #a0cfff !important;
}
</style>
